当前位置: 首页 >文章 > JS的所谓的第七种数据类型Symbol
收藏
分享

JS的所谓的第七种数据类型Symbol

举报李游Leo李游Leo发布于 2020-05-091565阅读2点赞
Symbol是什么数据类型...

首先,为什么说叫所谓呢?

因为在2007年之前Js给予我们typeof解析数据类型的一共有六种(一直有争议,但是我们暂时就按typeof来算)

  • 'function'

  • 'Number'

  • 'Object'

  • 'boolean'

  • 'String'

  • 'undefined'

但当我们去 typeof Symbol () 的时候,会惊奇的发现,返回了一个

‘symbol’

首先肯定要有疑问,这货是啥?

当然第一种想法其实就是肯定很强大。因为前六种已经强大的一种地步了,这货肯定也一定非常强大。

首先我们先带着我们的好奇心一步一步来看看这个鬼东西。

首先先验证一下它是不是对象。

通过我先说一下我对对象研究的他有三种机制:

  • 只要是对象就可以引用。

  • 只要是对象都可以赋予私有属性。

  • 对象都不相等。

那么

var a = Symbol();

a.b = 10;//  赋予私有属性

a.b // undefined

看来这货不是个对象,既然不是对象我们来看看它的一些别的特性。

首先在 api 上 Symbol 提供了两个方法第一个是 for 另外一个是 keyFor 。

var s1 = Symbol.for('abc');

var s2 = Symbol.for('abc');

Symbol() === Symbol() //false

s1 === s2    //true

Symbol.keyFor(s1)// 'abc'

当然这两个看起来比较容易 似乎就是一个赋予一个值然后就会把原来的值吐出来,当然真是原来的值么?带着这样的疑问我又继续做了一些实验。

var s1 = Symbol.for([1,2,3]);

Symbol.keyFor(s1); //  "1,2,3" 字符串的 1,2,3

 var s1 = Symbol.for(function (){});

Symbol.keyFor(s1); "function (){}"   字符串的fn;

你会发现这货你存的东西只会以字符串的东西吐出来。

当然这个东西官方说由于每一个 Symbol 值都是不相等的,这意味着 Symbol 值可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性。这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。

也就是说可以作为存在 json 中让 key 永远不相等。OK ,那么就完全可以这样:

 var a = {};
       a[Symbol()]= 'Hello!';
       a[Symbol()]= 'Hello!';
       a[Symbol()]= 'Hello!'; 

      console.log(a);

      Object

          Symbol(): "Hello!"

          Symbol(): "Hello!"

          Symbol(): "Hello!"

      __proto__: Object 

你会发现出现了连续的三个 a的属性 都是hello 并且没有覆盖 。也就是说这么写的话可以有效的防止其json重名问题,不过拿起来就非常费劲了。

 for(var i in a){
           console.log(i +',' +a[i]) //没有任何的东西 
      }      

当然这就比较可以可疑了,json 用 symbol 存上东西了,但是又用 for in 拿不到。也就说如果直接这么赋值 json 认,但是 for in 循环不认,而且咱们也拿不到。

但是换一种方式就没问题了。用变量存的话,虽然虽然 for in 拿不到,但是咱们可以拿到值。

var a = Symbol('aaa');

      b = {};

      b[a] = 10 ;
      console.log(b[a])//10 

轻松拿到值。其实不难看出来 Symbol 对 for in 不是很友好,但是 对 json 很友好。

这时如果使用别的方法拿值呢?顾名思义,Object.getOwnPropertyNames() 是拿对象私有属性的的方法,我们来试试。

 let b = {};
      b[Symbol()]=10;
      b[Symbol()]=15;
      Object. getOwnPropertyNames(b) //

可以理解为:其实 Symbol 不作为 b 的私有属性存在。拿能不能拿到呢?其实也能拿到。他提供了一个 getOwnPropertySymbols 方法可以让我找到存在内存里的 Symbol 。

例如:

 let a = {};
      a[Symbol()]=10;
      a[Symbol()]=15;
      Object.getOwnPropertySymbols(a) //[Symbol(),Symbol()] //这里面以数组的形式返回了 咱们使用的两个Symbol();
      Object.getOwnPropertySymbols(a)[0]//Symbol() 第一个Symbol()
      a[Object.getOwnPropertySymbols(a)[0]]//10 拿到存在的这个值。

其实知道是数组后 我们就可以循环  obj.getOwnPropertySymbols(a) 这个东西 然后输出值了。其实说回来只是换了一种方法拿值,存值。而这种方法更安全更隐蔽而已。

而Symbol还有一些比较特殊的特性。js中的~(按位非) 是一个比较强势的转换number的东西。

例如:

~NaN  //-1

~function (){}//-1

~undefined   //-1
var a = function (){};
~a()  //-1
~new a() //-1

基本任何东西都能转成number,而:

~Symbol  //-1
~Symbol() //报错 

似乎说明了 其跟function 有着本质的区别,另外呢,Symbol值不能与其他类型的值进行运算,会报错。

var sym = Symbol('My symbol');

"your symbol is " + sym     // TypeError: can't convert symbol to string   es5之前的报错

`your symbol is ${sym}`     // TypeError: can't convert symbol to string   es6字符串照样的报错

另外,Symbol值也可以转为布尔值,但是不能转为数值。这些都是Symbol的一些小特性。

var sym = Symbol();

Boolean(sym) // true

!sym  // false

Number(sym) // TypeError

sym + 2 // TypeError 

其实来说Symbol作为一个新的数据类型 最强的而不是干以上的这些事而是一些配合原型方法的一些开关,可以强化方法的使用。

比如说 Symbol.isConcatSpreadable 这个方法,咱们都知道 正常的数组concat方法是连接字符串。

let arr = ['c', 'd'];

['a', 'b'].concat(arr2,'e') //['a','b','c','d','e'];

而我们一旦把开关打开后会发现一些意想不到的结果。

let arr2 = ['c', 'd'];

arr2[Symbol.isConcatSpreadable] = false;

['a', 'b'].concat(arr2, 'e') //['a','b',['c','d'],'e']

会发现以数组的形式插入到里面了。当然他还包括了一些别的方法,例如,他可以测试 ES6 新增的内置对象方法 Symbol.toStringTag 。

JSON[Symbol.toStringTag]:'JSON'

Math[Symbol.toStringTag]:'Math'

Module对象M[Symbol.toStringTag]:'Module'

ArrayBuffer.prototype[Symbol.toStringTag]:'ArrayBuffer'  

DataView.prototype[Symbol.toStringTag]:'DataView'

Map.prototype[Symbol.toStringTag]:'Map'

Promise.prototype[Symbol.toStringTag]:'Promise'

Set.prototype[Symbol.toStringTag]:'Set'

%TypedArray%.prototype[Symbol.toStringTag]:'Uint8Array'等

WeakMap.prototype[Symbol.toStringTag]:'WeakMap'

WeakSet.prototype[Symbol.toStringTag]:'WeakSet'

%MapIteratorPrototype%[Symbol.toStringTag]:'Map Iterator'

%SetIteratorPrototype%[Symbol.toStringTag]:'Set Iterator'

%StringIteratorPrototype%[Symbol.toStringTag]:'String Iterator'

Symbol.prototype[Symbol.toStringTag]:'Symbol'

Generator.prototype[Symbol.toStringTag]:'Generator'

GeneratorFunction.prototype[Symbol.toStringTag]:'GeneratorFunction' 

不过,用 ES5 之前的方法依然也可以检验出来内置对象,所以 Symbol 就是更规范化而已,就用 map 举例。

Object.prototype.toString.call(new Map())//'[object Map]'

别的内置对象也是同理。Symbol.unscopables 也是Symbol一个比较有意思的东西。可以找到对象内哪些属性被with排除。

Object.keys(Array.prototype[Symbol.unscopables])//['copyWithin', 'entries', 'fill', 'find', 'findIndex', 'keys']

以数组的形式返回 也就是说 这些属性会被with排除。其实这些只是Smybol的冰山一角,更多的是Symbol是服务于ES6中。让我们继续慢慢探索好了。


0条评论
别默默看啦~登录/注册一起参与讨论吧~

暂无评论

请选择举报理由

违反法律法规

侵犯个人权益

有害网站环境

更多训练营>>

为你推荐 · 训练营(全勤打卡报名费全额返累计全额返用户133,637人)

电商海报设计训练营
距离开班仅剩9天66人已报名
【5月】零基础手绘插画训练营
距离开班仅剩9天55人已报名
【5月】零基础动态表情包创作训练营
距离开班仅剩26天15人已报名
特惠
充值
7折购
今日还在继续学习的你,太棒了!
7
折扣券可用于
年费无限VIP
立 即
使 用
此活动优惠不可与其他活动叠加使用
有效期:000000
消息
登录即可查看消息记录
建议
意见
官方
客服
在线咨询客服热线

您可以与在线客服进行沟通获得帮助

工作日:9:00~22:00节假日:9:00~18:00

联系在线客服

您可以电话联系客服进行沟通获得帮助

工作日:9:30~18:30

400-862-9191
虎课
积分
免费学习89000+个教程!
配套素材、源文件一键下载!
昨日学员已学习了27,078
并提交了210份作业!
登录后立即学习!
loading
微信扫码关注即可登录
您需要同意协议才可以进行登录
登录虎课网,每天免费学课程全站 89000+ 视频会员教程 | 每日可免费学 1
为确保账户信息安全
请先进行真实姓名验证后进行充值付款
立即验证